﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Reflection;
using System.ServiceModel.Activation;
using System.Text;
using UFIDA.U9.WSS.ProxyService.Behavior.Endpoint;
using UFIDA.U9.WSS.ProxyService.Exceptions;
using UFIDA.U9.WSS.ProxyService.Models;
using UFIDA.U9.WSS.ProxyTestService.Interfaces;
using UFIDA.U9.WSS.ProxyTestService.Models;
using UFIDA.U9.WSS.ProxyTestService.Utils;
using UFSoft.UBF;
using UFSoft.UBF.Service.Base;
using UFSoft.UBF.Sys.Database;
using UFSoft.UBF.Util.Context;
using UFSoft.UBF.Util.DataAccess;

namespace UFIDA.U9.WSS.ProxyTestService.Services
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ProxyTestService : IProxyTestService
    {
        /// <summary>
        ///     测试连接
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        [Description("测试连接")]
        [DisableU9Context]
        public ReturnMessage<CommonObject> TestConnection(CommonObject obj)
        {
            return new ReturnMessage<CommonObject>(obj);
        }

        /// <summary>
        ///     查询服务信息
        /// </summary>
        /// <param name="queryString"></param>
        /// <returns></returns>
        [Description("查询服务信息")]
        public ReturnMessage<List<BPSVType>> QueryBPSVType(string queryString)
        {
            if (string.IsNullOrWhiteSpace(queryString))
                throw new ArgumentException("queryString is empty");
            string[] arrQueryStr = queryString.Split(' ');
            StringBuilder sb = new StringBuilder();
            sb.Append(@"SELECT B.DisplayName,
                       A.FullName,
                       C.AssemblyName,
                       C.Kind,
                       A.TransactionType
                FROM UBF_MD_Class AS A
                    LEFT JOIN UBF_MD_Class_Trl AS B
                        ON A.Local_ID = B.Local_ID
                    LEFT JOIN UBF_MD_Component AS C
                        ON A.MD_Component_ID = C.ID
                    LEFT JOIN UBF_MD_Component_Trl AS D
                        ON C.Local_ID = D.Local_ID
                WHERE (
                          C.Kind = 'SV'
                          OR C.Kind = 'BP'
                      )");
            DataParamList dataParams = new DataParamList();
            sb.Append(" AND B.SysMLFlag = @SysMLFlag");
            dataParams.Add(DataParamFactory.CreateInput("SysMLFlag", PlatformContext.Current.Culture, DbType.String));
            for (int i = 0; i < arrQueryStr.Length; i++)
            {
                string str = arrQueryStr[i];
                string paramName = "param" + i;
                if (string.IsNullOrWhiteSpace(str)) continue;
                sb.Append(" AND ");
                sb.AppendFormat("CHARINDEX(@{0}, A.FullName + ' ' + B.DisplayName) > 0", paramName);
                dataParams.Add(DataParamFactory.CreateInput(paramName, str, DbType.String));
            }

            sb.Append(" ORDER BY B.DisplayName,A.FullName,C.AssemblyName,C.Kind");
            DataSet dataSet;
            DataAccessor.RunSQL(DatabaseManager.GetCurrentConnection(), sb.ToString(), dataParams, out dataSet);
            List<BPSVType> dataList = new List<BPSVType>();
            if (dataSet == null || dataSet.Tables.Count <= 0 || dataSet.Tables[0].Rows.Count <= 0)
                return new ReturnMessage<List<BPSVType>>(dataList);
            foreach (DataRow row in dataSet.Tables[0].Rows)
            {
                BPSVType bpsv = new BPSVType();
                bpsv.DisplayName = AsString(row, "DisplayName");
                bpsv.FullName = AsString(row, "FullName");
                bpsv.AssemblyName = AsString(row, "AssemblyName");
                bpsv.Kind = AsString(row, "Kind");
                //事务类型
                int transactionType = AsInt(row, "TransactionType");
                switch (transactionType)
                {
                    case 0:
                        bpsv.TransactionType = "Required";
                        break;
                    case 1:
                        bpsv.TransactionType = "RequiresNew";
                        break;
                    case 2:
                        bpsv.TransactionType = "Supported";
                        break;
                    case 3:
                        bpsv.TransactionType = "NotSupported";
                        break;
                    case 4:
                        bpsv.TransactionType = "EnforceConnection";
                        break;
                    default:
                        bpsv.TransactionType = string.Empty;
                        break;
                }

                dataList.Add(bpsv);
            }

            return new ReturnMessage<List<BPSVType>>(dataList);
        }

        /// <summary>
        ///     通过BPSV类型对象获取代理类型对象
        /// </summary>
        /// <param name="bpsvType"></param>
        /// <returns></returns>
        [Description("通过BPSV类型对象获取代理类型对象")]
        public ReturnMessage<string> GetProxyType(BPSVType bpsvType)
        {
            if (bpsvType == null)
                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException, "bpsvType is null");
            if (string.IsNullOrEmpty(bpsvType.AssemblyName))
                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException,
                    "bpsvType.AssemblyName is empty");
            if (string.IsNullOrEmpty(bpsvType.FullName))
                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException, "bpsvType.FullName is empty");
            //代理类dll
            string proxyAssemblyName = (bpsvType.AssemblyName.ToLower().EndsWith(".dll")
                                           ? bpsvType.AssemblyName.Substring(0, bpsvType.AssemblyName.Length - 4)
                                           : bpsvType.AssemblyName)
                                       + ".Agent.dll";
            Assembly assembly = TypeManager.TypeLoader.ProbeAssembly(proxyAssemblyName);
            if (assembly == null)
                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException,
                    string.Format("Assembly {0} is not exist", proxyAssemblyName));
            string[] arrFullName = bpsvType.FullName.Split('.');
            string proxyClassName = arrFullName[arrFullName.Length - 1] + "Proxy";
            string agentTypeFullName = string.Join(".", arrFullName.Take(arrFullName.Length - 1)) + ".Proxy." +
                                       proxyClassName;
            Type agentType = null;
            List<Type> types = new List<Type>();
            foreach (Type searchType in assembly.GetTypes())
            {
                if (searchType.FullName == agentTypeFullName)
                {
                    agentType = searchType;
                    break;
                }

                if (searchType.Name == proxyClassName && searchType.IsSubclassOf(typeof(ProxyBase)))
                    types.Add(searchType);
            }

            if (agentType != null)
                return new ReturnMessage<string>(string.Concat(agentType.FullName, ",", proxyAssemblyName));
            if (types.Count == 0)
                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException, string.Format(
                    "className: {0} in {1} no exist", proxyClassName,
                    proxyAssemblyName));
            if (types.Count > 1)
                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException, string.Format(
                    "className: {0} in {1} no only one", proxyClassName,
                    proxyAssemblyName));
            agentType = types[0];
            return new ReturnMessage<string>(string.Concat(agentType.FullName, ",", proxyAssemblyName));
        }

        /// <summary>
        ///     获取代理对象
        /// </summary>
        /// <param name="proxyType"></param>
        /// <param name="useDataContract"></param>
        /// <param name="requestDataMaxExpandDepth"></param>
        /// <returns></returns>
        [Description("获取代理对象")]
        public ReturnMessage<ProxyData> GetProxyData(string proxyType, bool useDataContract,
            int requestDataMaxExpandDepth)
        {
            ProxyBase proxyBase = ProxyHelper.GetProxyBaseObject(proxyType);
            if (proxyBase == null)
                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException, string.Format(
                    "proxyType:{0} is not proxy base object",
                    proxyType));
            ProxyData proxyData = new ProxyData();
            proxyData.ProxyType = proxyType;
            proxyData.UseDataContract = useDataContract;
            proxyData.RequestDataMaxExpandDepth = requestDataMaxExpandDepth;
            proxyData.ProxyJsonString =
                ProxyJsonHelper.ProxyObjectToJsonString(proxyBase, useDataContract, true, requestDataMaxExpandDepth);
            return new ReturnMessage<ProxyData>(proxyData);
        }

        /// <summary>
        ///     重新加载代理对象
        /// </summary>
        /// <param name="proxyData"></param>
        /// <returns></returns>
        [Description("重新加载代理对象")]
        public ReturnMessage<ProxyData> ReLoadProxy(ProxyData proxyData)
        {
            if (proxyData == null)
                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException, "proxyData is null");
            if (proxyData.ProxyType == null)
                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException, "proxy.ProxyType is null");
            if (string.IsNullOrEmpty(proxyData.ProxyJsonString))
                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException,
                    "proxy.ProxyJsonString is empty");
            string proxyType = proxyData.ProxyType;
            Type loadType = ProxyHelper.GetType(proxyType);
            if (loadType == null)
                throw new WSException(ExceptionCodes.ProxyServiceProxyTypePropertyIsIncorrect,
                    "proxyType is incorrect");
            ProxyBase proxyBase =
                ProxyJsonHelper.ProxyObjectFromJsonString(proxyData.ProxyJsonString,
                        loadType, proxyData.UseDataContract) as
                    ProxyBase;
            if (proxyBase == null)
                throw new WSException(ExceptionCodes.ProxyServiceProxyTypePropertyIsIncorrect, string.Format(
                    "proxyType:{0} is not proxy base object",
                    proxyType));
            proxyData.ProxyJsonString = ProxyJsonHelper.ProxyObjectToJsonString(proxyBase, proxyData.UseDataContract);
            return new ReturnMessage<ProxyData>(proxyData);
        }

        /// <summary>
        ///     执行请求
        /// </summary>
        /// <param name="proxyData"></param>
        /// <returns></returns>
        [Description("执行请求")]
        public ReturnMessage<string> ProxyDo(ProxyData proxyData)
        {
            if (proxyData == null)
                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException, "proxyData is null");
            if (proxyData.ProxyType == null)
                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException, "proxy.ProxyType is null");
            if (string.IsNullOrEmpty(proxyData.ProxyJsonString))
                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException,
                    "proxy.ProxyJsonString is empty");
            Type proxyType = ProxyHelper.GetType(proxyData.ProxyType);
            ProxyBase proxyBase =
                ProxyJsonHelper.ProxyObjectFromJsonString(proxyData.ProxyJsonString,
                        proxyType, proxyData.UseDataContract) as
                    ProxyBase;
            if (proxyBase == null)
                throw new WSException(ExceptionCodes.ProxyServiceProxyTypePropertyIsIncorrect, string.Format(
                    "proxyType:{0} is not proxy base object",
                    proxyType));
            MethodInfo methodInfo = proxyBase.GetType().GetMethod("Do", new Type[] { });
            if (methodInfo == null)
                throw new WSException(ExceptionCodes.ProxyServiceProxyTypePropertyIsIncorrect,
                    "no find Do() method in proxy object");
            try
            {
                //禁止检查下一个代理有效
                SessionObject.DisableCheckOneProxyEnabled();
                //反射调用
                object result = methodInfo.Invoke(proxyBase, null);
                ReturnMessage<string> ret = new ReturnMessage<string>();
                ret.IsSuccess = true;
                ret.Data = result == null
                    ? string.Empty
                    : ProxyJsonHelper.ProxyResultToJsonString(result, proxyData.UseDataContract);
                return ret;
            }
            catch (Exception ex)
            {
                throw new WSException(ExceptionCodes.ProxyServiceCallFail, string.Empty, ex);
            }
        }

        #region Other

        private static string AsString(DataRow dataRow, string columnName)
        {
            return AsString(dataRow, columnName, string.Empty);
        }

        private static string AsString(DataRow dataRow, string columnName, string defaultValue)
        {
            object value = dataRow[columnName];
            return Convert.IsDBNull(value) ? defaultValue : value.ToString();
        }

        public static int AsInt(DataRow dataRow, string columnName)
        {
            return AsInt(dataRow, columnName, default(int));
        }

        public static int AsInt(DataRow dataRow, string columnName, int defaultValue)
        {
            object value = dataRow[columnName];
            return Convert.IsDBNull(value) ? defaultValue : Convert.ToInt32(value);
        }

        #endregion
    }
}